一.List体系
  a.List体系特点:
     元素有顺序,元素有索引,可以存储重复元素
  b.ArrayList类
    1.ArrayList特有功能
        /**
         * ArrayList<E>类中的方法:
         *   boolean add(E e)
         *           将指定的元素添加到此列表的尾部。
         *  void add(int index, E element)
         *           将指定的元素插入此列表中的指定位置。
         *
         *  E get(int index)
         *           返回此列表中指定位置上的元素。
         *
         *
         *  E set(int index, E element)
         *           用指定的元素替代此列表中指定位置上的元素。
         *
         *  E remove(int index)
         *           移除此列表中指定位置上的元素。
         */
    2.ArrayList三种遍历方式
        /**
         * ArrayList类遍历(迭代)
         *   1.集合通用迭代方式:迭代器
         *   2.ArrayList特有的遍历方式,通过索引遍历
         *   3.增强for
         *
         */
     3.ArrayList底层原理
        /**
         * ArrayList底层原理
         *   1.ArrayList底层使用的是一个引用类型的数组才存储元素Object[] elementData
         *     第一次调用add()方法添加元素的时候,就会使用默认容量初始化这个数组
         *     int[] arr=new int[10];//这个数组中所有元素都是int类型,相当于一次性声明了10个int类型变量
         *     arr[0]=13; //相当于 int e0 = 13;
         *
         *     Object[] elementData = new Object[10]//这个数组中所 有元素都是Object类型,相当于一次性声明10个Object类型变量
         *     elementData[0]="张三" //相当于 Object e0 = "张三" 多态
         *     elementData[1]="李四" //相当于 Object e1 = "李四" 多态
         *
         *  2.ArrayList扩容思想
         *     当添加元素超过10个元素时候,此时ArrayList底层就会创建一个新的数组,长度为原来的1.5倍
         *      然后将原有的元素拷贝到新数组中去,最后把新添加的元素追加到最后一个老元素末尾
         *
         */

     4.ArrayList中存储自定义引用类型
        ArrayList此时指定的泛型就是自定义引用类型,也就是集合中存储的元素的类型
     5.ArrayList集合的特点:
        1.集合中元素有索引,有顺序,可以存储重复元素
        2.ArrayList集合增删慢,查询快
          a.查询快:因为ArrayList底层是一个数组,而数组有索引,我们根据索引可以直接取出元素

                  集合索引    0       1        2    3     4  ...  9
             ArrayList元素: "abc"   "def"   "ghk"  null null ... null
             获取"ghk":根据索引直接可以取出元素 get(2)
          b.增删慢:如果我们要增删一个元素,会导致这个元素后面的所有元素往前或者往后挪动,由于大量移动元素,导致ArrayList效率低
                  集合索引            0       1        2    3     4  ...  9
             ArrayList元素:         "abc"   "def"   "ghk"  null null .... null
             添加一个"ml"到0索引位置   "ml"    "abc"   "def"  "ghk" null ... null
             当我们添加一个元素的时候,该元素之后的元素都要依次往后移动一个位置

                  集合索引            0       1        2    3     4  ...  9
            ArrayList元素:         "abc"   "def"   "ghk"  null null .... null
            删除"abc"               "def"  "ghk"    null  null null .... null
            当我们删除一个元素的时候,该元素之后的元素都要依次往前移动一个位置

   c.LinkedList集合
      1.LinkedList特有方法
        /**
         * LinkedList中特有方法:
         *   void addFirst(E e)
         *            不断向集合的起始位置(开头位置)添加元素
         *   void addLast(E e)
         *            不断向集合的末尾位置(结尾位置)添加元素
         *
         *   E getFirst()
         *           获取起始位置的元素。
         *  E getLast()
         *           获取末尾位置的元素
         *
         *   E removeFirst()
         *            移除并返回起始位置的元素
         *    E removeLast()
         *           移除并返回末尾位置的元素
         */
      2.LinkedList底层原理&特点
         LinkedList底层使用的是双向链表
         LinkedList 查询慢,增删快
         ArrayList  查询快,增删慢
    d.HashSet集合
      1.HashSet特点
        /**
         * HashSet简单使用
         *   特点:
         *     1.不能存储重复元素
         *     2.存储元素的顺序和取元素的顺序不一定一致
         *     3.没有索引,无法通过索引操作集合中的元素
         */
      2.HashSet遍历方式
         迭代器遍历和增强for遍历

      3.HashSet保证唯一性原理
        /**
         * HashSet底层保证存储元素唯一的原理:
         *    新添加的元素与集合中已有的元素通过调用hashCode()方法比较哈希值
         *     如果两个元素的哈希值不同,新添加的元素直接存入
         *     如果两个元素的哈希值相同
         *        此时需要通过equals()方法比较两个元素内容,如果equals返回true,说明两个元素内容相同,此时新添加的元素就不再存入
         *        如果equals()方法返回false,说明两个元素内容不同,此时新添加的元素就要存入
         */
        我们一般重写equals()方法和hashCode()方法
            /**
             * 如果两个人的姓名和年龄均相同,返回true
             * 如果两人至少有一个属性不同,返回false
             * @param o
             * @return
             */
            @Override
            public boolean equals(Object o) {
                    Person p = (Person) o;
                    System.out.println(this.name+" "+p.name+" equals方法被调用");

                    if (this == o) return true;
                    if (!(o instanceof Person)) return false;
                    Person person = (Person) o;
                    return age == person.age &&
                    name.equals(person.name);
                    }


                /**
                 * 如果我们可以针对不同的人(至少有一个属性不同),直接通过hashCode()方法来判定
                 * 新添加元素是否存入,这样就可以减少equals()调用次数
                 * 那么我们一般根据这个类的所有属性来计算一个哈希值
                 * @return
                 */
                   /* @Override
                    public int hashCode() {
                        System.out.println(this.name + " hashCode方法被调用");
                        //return 0;
                        return name.hashCode() + age;
                    }*/

                @Override
                public int hashCode() {
                        return Objects.hash(name, age);
                        }

